﻿//TODO: BinaryDilation: This has to be tested

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// The dilation is applied on the binary image in a single pass. During the pass, if
    /// the pixel in hand is equal to binary 1, then apply the structuring element on the
    /// image by starting from that particular pixel as the origin. The sample project
    /// supposes that, in the thresholded image, the background is black and the
    /// foreground is white. If the sample image is not so, then you have to adjust
    /// accordingly.
    /// The dilattion can also be applied on the graylevel images also in a single pass.
    /// </summary>
    public class BinaryDilation : BaseForeBackgroundColorFilter
    {
        /// <summary>
        /// 
        /// </summary>
        protected byte[,] m_aSelection = new byte[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };

        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryDilation"/> class.
        /// </summary>
        public BinaryDilation()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryDilation"/> class.
        /// </summary>
        /// <param name="_aSelection">The _a selection.</param>
        public BinaryDilation(byte[,] _aSelection)
        {
            m_aSelection = _aSelection;
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryDilation"/> class.
        /// </summary>
        /// <param name="_binaryDilation">The _binary dilation.</param>
        internal BinaryDilation(BinaryDilation _binaryDilation)
        {
            m_aSelection = _binaryDilation.m_aSelection;
        }

        /// <summary>
        /// Gets or sets the selection.
        /// </summary>
        /// <value>The selection.</value>
        public byte[,] Selection
        {
            get { return m_aSelection; }
            set { m_aSelection = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap tempBitmap = _bitmap;
            UnsafeBitmap bitmap = (UnsafeBitmap)_bitmap.Clone();
            BitmapData bitmapData2 = tempBitmap.BitmapData; //tempBitmap.LockBits(new Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bitmapData = bitmap.BitmapData; //bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            byte[,] aElement = m_aSelection;

            int nBytesPerPixelCount = bitmap.BytesPerPixelCount;
            int nIncrease = bitmap.OffsetPointerIncrease;
            unsafe
            {
                byte* ptr = (byte*)bitmapData.Scan0;
                byte* tptr = (byte*)bitmapData2.Scan0;

                ptr += bitmapData.Stride + nBytesPerPixelCount;
                tptr += bitmapData.Stride + nBytesPerPixelCount;

                int nRemain = bitmapData.Stride - bitmapData.Width * nBytesPerPixelCount; //bitmapData.Stride - bitmapData.Width * 3;

                int nHeight = bitmapData.Height;
                int nWidth = bitmapData.Width;

                int i = 0;
                int j = 0;
                int k = 0;
                int l = 0;

                for (i = 1; i < nHeight - 1; i++)
                {
                    for (j = 1; j < nWidth - 1; j++)
                    {
                        if (ptr[0] == 255)
                        {
                            byte* temp = tptr - bitmapData.Stride - nBytesPerPixelCount; //tptr - bitmapData.Stride - 3;

                            for (k = 0; k < 3; k++)
                            {
                                for (l = 0; l < 3; l++)
                                {
                                    temp[bitmapData.Stride * k + l * nBytesPerPixelCount] = temp[bitmapData.Stride * k + l * nBytesPerPixelCount + 1] = temp[bitmapData.Stride * k + l * nBytesPerPixelCount + 2] = (byte)(aElement[k, l] * 255);
                                    //temp[bitmapData.Stride * k + l * 3] = temp[bitmapData.Stride * k + l * 3 + 1] = temp[bitmapData.Stride * k + l * 3 + 2] = (byte)(aElement[k, l] * 255);
                                }
                            }
                        }
                        ptr += nIncrease; //ptr += 3;
                        tptr += nIncrease; //tptr += 3;
                    }
                    ptr += nRemain + nBytesPerPixelCount*2; //ptr += nRemain + 6;
                    tptr += nRemain + nBytesPerPixelCount*2; //tptr += nRemain + 6;
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new BinaryDilation(this);
        }
    }
}
